package com.jinmdz.fmis.api.global;

import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.EResultCode;
import com.jinmdz.fmis.core.util.LogUtil;
import com.jinmdz.fmis.core.wrapper.ResultWrapper;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.io.IOException;

/**
 * 全局异常处理器
 *
 * @author LiCongLu
 * @date 2019-12-20 09:32
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 运行时异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public BaseResult runtimeExceptionHandler(RuntimeException e) {
        return resultFormat("RuntimeException", e);
    }

    /**
     * 空指针异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public BaseResult nullPointerExceptionHandler(NullPointerException e) {
        return resultFormat("NullPointerException", e);
    }

    /**
     * 类型转换异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ClassCastException.class)
    public BaseResult classCastExceptionHandler(ClassCastException e) {
        return resultFormat("ClassCastException", e);
    }

    /**
     * IO异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(IOException.class)
    public BaseResult iOExceptionHandler(IOException e) {
        return resultFormat("IOException", e);
    }

    /**
     * 未知方法异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(NoSuchMethodException.class)
    public BaseResult noSuchMethodExceptionHandler(NoSuchMethodException e) {
        return resultFormat("NoSuchMethodException", e);
    }

    /**
     * 数组越界异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public BaseResult indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException e) {
        return resultFormat("IndexOutOfBoundsException", e);
    }

    /**
     * 为获取处理异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public BaseResult noHandlerFoundExceptionHandler(NoHandlerFoundException e) {
        return resultFormat("NoHandlerFoundException", e);
    }

    /**
     * 上传文件过大错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MaxUploadSizeExceededException.class})
    public BaseResult requestTypeMismatch(MaxUploadSizeExceededException e) {
        return resultFormat("MaxUploadSizeExceededException", e);
    }

    /**
     * 400错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public BaseResult requestNotReadable(HttpMessageNotReadableException e) {
        return resultFormat("HttpMessageNotReadableException", e);
    }

    /**
     * 400错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({TypeMismatchException.class})
    public BaseResult requestTypeMismatch(TypeMismatchException e) {
        return resultFormat("TypeMismatchException", e);
    }


    /**
     * 400错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public BaseResult requestMissingServletRequest(MissingServletRequestParameterException e) {
        return resultFormat("MissingServletRequestParameterException", e);
    }

    /**
     * 405错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public BaseResult request405(HttpRequestMethodNotSupportedException e) {
        return resultFormat("HttpRequestMethodNotSupportedException", e);
    }

    /**
     * 406错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public BaseResult request406(HttpMediaTypeNotAcceptableException e) {
        return resultFormat("HttpMediaTypeNotAcceptableException", e);
    }

    /**
     * 500错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public BaseResult server500(RuntimeException e) {
        return resultFormat("RuntimeException", e);
    }

    /**
     * 栈溢出
     *
     * @param error
     * @return
     */
    @ExceptionHandler({StackOverflowError.class})
    public BaseResult requestStackOverflow(StackOverflowError error) {
        return resultFormat("StackOverflowError", error);
    }

    /**
     * 创建事务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({CannotCreateTransactionException.class})
    public BaseResult requestCannotCreateTransactionException(CannotCreateTransactionException e) {
        return resultFormat("CannotCreateTransactionException", e);
    }

    /**
     * 其他错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({Exception.class})
    public BaseResult exception(Exception e) {
        return resultFormat("Exception", e);
    }

    /**
     * 返回异常信息
     *
     * @param code
     * @param e
     * @param <T>
     * @return
     */
    private <T extends Throwable> BaseResult resultFormat(String code, T e) {
        if (e.getCause() != null) {
            code = e.getCause().getClass().getSimpleName();
        }
        String remark = "引发异常类，" + code + "；异常信息，" + e.getMessage();
        LogUtil.error(remark, e);
        return ResultWrapper.getResult(EResultCode.CODE500).setRemark(remark);
    }
}